import 'package:flutter/material.dart';
import 'package:x3_component_core/x3_component_core.dart';

/// 自定义下拉刷新 上拉加载的ListView
class BaseRefreshContainerComponent extends StatefulWidget {
  /// 是否需要上拉加载更多
  final bool needLoading;

  /// 上拉加载的回调事件
  final LoadingFuture onLoading;

  /// 刷新数据
  final RefreshFuture onRefresh;

  /// 子item的创建函数
  final Widget Function(BuildContext context, int index, dynamic item) builder;

  /// 分割线
  final Widget Function(BuildContext context, int index, dynamic item) separatorBuilder;

  /// 是否默认加载数据
  final bool autoLoad;

  /// 获取下拉刷新的RefreshIndicatorState 通用
  final void Function(GlobalKey<RefreshIndicatorState>) getRefreshIndicatorState;

  /// 内边距
  final EdgeInsets padding;

  /// 预加载
  final double cacheExtent;

  /// 列表顶部的Widget
  final Widget headerWidget;

  /// 构造函数
  BaseRefreshContainerComponent({Key key, @required this.builder, @required this.separatorBuilder, @required this.getRefreshIndicatorState, @required this.onRefresh, this.padding = EdgeInsets.zero, this.autoLoad = true, this.needLoading = false, this.onLoading, this.cacheExtent, this.headerWidget})
      : assert(separatorBuilder != null),
        super(key: key);

  @override
  _BaseRefreshContainerComponentState createState() => _BaseRefreshContainerComponentState();
}

class _BaseRefreshContainerComponentState extends State<BaseRefreshContainerComponent> {
  final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey = new GlobalKey<RefreshIndicatorState>();

  /// 数据源
  List<Map<String, dynamic>> _items;

  /// 加载状态
  LoadingStatusEnum _loadingStatus = LoadingStatusEnum.LoadingComplete;

  @override
  void initState() {
    super.initState();
    this._onRefreshData();
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      widget.getRefreshIndicatorState(_refreshIndicatorKey);
    });
  }

  /// 刷新数据
  Future _onRefreshData() async {
    if (widget.autoLoad == true && widget.onRefresh != null) {
      List<Map<String, dynamic>> items = await widget.onRefresh();
      if (this.mounted == true) {
        setState(() {
          this._items = items;
          this._loadingStatus = LoadingStatusEnum.LoadingComplete;
        });
      }
    }
  }

  /// 加载更多数据
  Future _onLoadingData() async {
    if (widget.needLoading == true && widget.onLoading != null) {
      if (this.mounted == true) {
        setState(() {
          this._loadingStatus = LoadingStatusEnum.Loading;
        });
      }
      List<Map<String, dynamic>> items = await widget.onLoading();
      if (this.mounted == true) {
        if (items.length == 0) {
          setState(() {
            this._loadingStatus = LoadingStatusEnum.NoMore;
          });
        } else {
          setState(() {
            this._items.addAll(items);
            this._loadingStatus = LoadingStatusEnum.LoadingComplete;
          });
        }
      }
    }
  }

  /// 构建子Item项
  Widget _buildListItem(BuildContext context, int index) {
    return widget.headerWidget == null ? _buildListItemNoHasHeaderWidget(context, index) : _buildListItemHasHeaderWidget(context, index);
  }

  Widget _buildListItemHasHeaderWidget(BuildContext context, int index) {
    if (index == 0) {
      return widget.headerWidget;
    }
    if (this._items.length == 0) return _buildNoDataWidget();
    if (index < this._items.length + 1) {
      return widget.builder(context, index, this._items[index - 1]);
    }
    if (index == this._items.length + 1) return _buildBottomLoadingStateWidget();
    return SizedBox();
  }

  Widget _buildListItemNoHasHeaderWidget(BuildContext context, int index) {
    if (this._items.length == 0) return _buildNoDataWidget();
    if (index != this._items.length) return widget.builder(context, index, this._items[index]);
    if (index == this._items.length) return _buildBottomLoadingStateWidget();
    return SizedBox();
  }

  Widget _buildListSeparatorItem(BuildContext context, int index) {
    return widget.separatorBuilder(context, index, <String, dynamic>{});
  }

  /// 构建底部加载更多的动画
  Widget _buildBottomLoadingStateWidget() {
    switch (this._loadingStatus) {
      case LoadingStatusEnum.Loading:
        return BaseBottomLoadingComponent();
        break;
      case LoadingStatusEnum.LoadingComplete:
        return null;
        break;
      case LoadingStatusEnum.NoMore:
        return BaseNoMoreComponent();
        break;
    }
    return null;
  }

  /// 构建没有数据时的显示
  Widget _buildNoDataWidget() {
    if (this._items.length == 0) {
      return Padding(padding: EdgeInsets.symmetric(vertical: 20.0), child: BaseEmptyComponent());
    }
    return SizedBox();
  }

  @override
  Widget build(BuildContext context) {
    return this._items == null ? BaseLoadingComponent() : _buildRefreshIndicatorListViewWidget();
  }

  /// 创建列表
  Widget _buildRefreshIndicatorListViewWidget() {
    Color color = Theme.of(context).primaryColor == Colors.white ? Theme.of(context).textTheme.bodyText2.color : Theme.of(context).primaryColor;
    return NotificationListener<ScrollNotification>(
      child: RefreshIndicator(
        key: _refreshIndicatorKey,
        color: color,
        onRefresh: _onRefreshData,
        child: _buildListViewWidget(),
      ),
      onNotification: _onScrollNotification,
    );
  }

  Widget _buildListViewWidget() {
    final int initCount = (this._items.length == 0 || widget.needLoading == true) ? this._items.length + 1 : this._items.length;
    final int count = widget.headerWidget != null ? initCount + 1 : initCount;
    return ListView.separated(
      cacheExtent: widget.cacheExtent,
      padding: widget.padding,
      separatorBuilder: _buildListSeparatorItem,
      itemBuilder: _buildListItem,
      itemCount: count,
      physics: const AlwaysScrollableScrollPhysics(),
      // 注意这里一定要加这个属性 不然无法下拉刷新
      shrinkWrap: true,
    );
  }

  bool _onScrollNotification(ScrollNotification scrollInfo) {
    /// 当前滚动的高度
    double currentScrollPixels = scrollInfo.metrics.pixels;

    /// 最大可滚动的高度 ( 如果当前的最大可滚动高度为0 则表明当前ListView没有占满当前屏幕 )
    double maxScrollPixels = scrollInfo.metrics.maxScrollExtent;
    // 需要确保是纵向的滚动（如果逐渐内有嵌套横向滚动，横向滚动到底也会触发当前事件）
    if (scrollInfo.metrics.axis == Axis.vertical && currentScrollPixels == maxScrollPixels && maxScrollPixels != 0.0 && this._loadingStatus == LoadingStatusEnum.LoadingComplete) {
      _onLoadingData();
    }
    return true;
  }
}
